home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Celestin Apprentice 7
/
Apprentice-Release7.iso
/
Source Code
/
Pascal
/
Snippets
/
Map
/
Map.p
< prev
next >
Wrap
Text File
|
1997-04-19
|
12KB
|
477 lines
program Map;
uses
{$IFC UNDEFINED THINK_PASCAL}
Types, QuickDraw, Menus, ToolUtils, Resources, {}
SegLoad, Events, Processes, Windows, Dialogs,
{$ELSEC}
{$ENDC}
QDOffScreen, Palettes, TransSkel;
const
kMaxAngle = 360 * 4; {NOT angle, but number of pixels wide! 360*2 is ok on 68k}
kFixedDigits = 8;
kFixedOne = 256; {2 ** kFixedDigits}
kFixedHalf = kFixedOne div 2;
kIntMask = $ffffff00;
kSignMask = $ff000000;
kAngle30 = kMaxAngle div 12;
kAngle60 = kMaxAngle div 6;
kAngle90 = kMaxAngle div 4;
kAngle120 = kMaxAngle div 3;
kAngle180 = kMaxAngle div 2;
kAngle15 = kMaxAngle div 24;
kAngle10 = kMaxAngle div 60;
kAngle5 = kMaxAngle div 72;
kViewAngle = kMaxAngle div 8; {8}
kFullView = Longint(kViewAngle) * 2;
kMaxRows = 200;
kHalfRows = kMaxRows div 2 * 0;
kMaxRay1 = 20; {How far with step 1?}
kMaxRay2 = 40; {How far with step 2?}
kMaxRay = 80; {How far with step the rest (step 4)?}
kMapSizeH = 256;
kMapSizeV = 256;
kMapMaskH = kMapSizeH - 1; {For BitAnd with coordinates!}
kMapMaskV = kMapSizeV - 1;
kMapSizeFixedH = kMapSizeH * kFixedOne;
kMapSizeFixedV = kMapSizeV * kFixedOne;
kMapMaskFixedH = kMapSizeFixedH - 1; {For BitAnd with coordinates!}
kMapMaskFixedV = kMapSizeFixedV - 1;
var
m: MenuHandle;
dummy: Boolean;
r: Rect;
w: WindowPtr;
gOffscreen: GrafPtr;
var
playerX, playerY, playerZ: Longint;
direction: Longint;
sinTable, cosTable: array[0..kMaxAngle] of Longint;
type
ByteArr = packed array[0..99999] of Byte;
ByteArrPtr = ^ByteArr;
var
map, colorScreen: GrafPtr;
offscreenPixels, mapPixels, colorPixels: ByteArrPtr;
offscreenRow, mapRow, colorRow: Longint;
boundsRect, mapBoundsRect: Rect;
c: RGBColor;
col: Integer;
var
rowTable, dyTable: array[0..kMaxRows] of Longint;
mapRowTable: array[0..kMapSizeV] of Longint;
const
kFokal = 50; {Lower is more flat. 50 is OK.}
kStartHeight = 80; {Camera height - should be variable}
procedure Render;
type
IntPtr = ^Integer;
var
x, y, z: Longint; {Ray position}
dx, dz, dy: Longint; {Ray direction}
dist, dDist: Integer; {Number of steps so far}
screenX, screenY, newscreeny: Integer; {Pixel coordinates}
angle: Integer; {Ray direction}
height: Integer;
mapBase, mapTableBase, offBase, rowTableBase: Longint;
tableP: IntPtr;
mapP, offP: Ptr;
Pixel: Byte;
finish: Integer;
const
{q = true;}
kBackPixValue = 205;
procedure RayStep;
begin
tableP := IntPtr(mapTableBase + BSL(BSR(z, kFixedDigits), 2));
mapP := Ptr(mapBase + tableP^ + BSR(x, kFixedDigits));
height := mapP^;
height := mapPixels^[mapRowTable[BSR(z, kFixedDigits)] + BSR(x, kFixedDigits)]; {Height of ground}
if y < height then
begin
newscreeny := (playerY - height) * kFokal div dist - kHalfRows; {We could make a table for this, but it would be 2D, i.e. big.}
pixel := colorPixels^[mapRowTable[BSR(z, kFixedDigits)] + BSR(x, kFixedDigits)];
offP := Ptr(offBase + rowTable[screenY] + screenX);
if newscreeny < 0 then
newscreeny := 0;
if newscreeny < screenY then
begin
finish := screenY - newscreeny;
while finish >= 4 do
begin
offP^ := pixel;
offP := Ptr(Longint(offP) - offscreenRow);
offP^ := pixel;
offP := Ptr(Longint(offP) - offscreenRow);
offP^ := pixel;
offP := Ptr(Longint(offP) - offscreenRow);
offP^ := pixel;
offP := Ptr(Longint(offP) - offscreenRow);
finish := finish - 4;
end;
while finish >= 1 do
begin
offP^ := pixel;
offP := Ptr(Longint(offP) - offscreenRow);
finish := finish - 1;
end;
screenY := newscreeny;
{for screenY := screenY downto newscreeny do}
{begin}
{offP^ := pixel;}
{offP := Ptr(Longint(offP) - offscreenRow);}
{Not so good:offscreenPixels^[rowTable[screenY] + screenX] := pixel;}
{end}
end
else
begin {If we get here, something is wrong.}
end;
{dy := -screenY * kFixedOne div kFokal; {slope when at screen height screenY!}
dy := dyTable[screenY];
y := height;
end;
dist := dist + dDist;
x := BAnd(x + dx, kMapMaskFixedH);
z := BAnd(z + dz, kMapMaskFixedV);
y := y + dy;
end; {RayStep}
begin {Render}
for screenX := 0 to kFullView do
begin
angle := (direction - (screenX - kViewAngle) + kMaxAngle) mod kMaxAngle; {always in interval 0..kMaxAngle}
{Double the step to increase speed.}
screenY := kMaxRows - 1;
dist := 1;
dDist := 1;
dx := cosTable[angle];
dz := sinTable[angle];
dy := dyTable[screenY];
x := playerX;
z := playerZ;
y := playerY;
mapBase := Longint(mapPixels);
mapTableBase := Longint(@mapRowTable);
offBase := Longint(offscreenPixels);
rowTableBase := Longint(@rowTable);
repeat
RayStep;
until (screenY <= 0) or (dist > kMaxRay1);
dx := dx * 2;
dy := dy * 2;
dz := dz * 2;
dDist := dDist * 2;
repeat
RayStep;
until (screenY <= 0) or (dist > kMaxRay2);
dx := dx * 2;
dy := dy * 2;
dz := dz * 2;
dDist := dDist * 2;
repeat
RayStep;
until (screenY <= 0) or (dist > kMaxRay);
{Paint sky!}
{This can be replaced by copying in pixels from a background picture.}
if screenY > 0 then
begin
finish := screenY;
while finish >= 4 do
begin
offP^ := kBackPixValue;
offP := Ptr(Longint(offP) - offscreenRow);
offP^ := kBackPixValue;
offP := Ptr(Longint(offP) - offscreenRow);
offP^ := kBackPixValue;
offP := Ptr(Longint(offP) - offscreenRow);
offP^ := kBackPixValue;
offP := Ptr(Longint(offP) - offscreenRow);
finish := finish - 4;
end;
while finish >= 1 do
begin
offP^ := kBackPixValue;
offP := Ptr(Longint(offP) - offscreenRow);
finish := finish - 1;
end;
screenY := 0;
end;
{for screenY := screenY downto 0 do}
{begin}
{offscreenPixels^[screenY * offscreenRow + screenX] := kBackPixValue;}
{end;}
if false then
begin
ForeColor(redColor);
MoveTo(BSR(x, kFixedDigits) + 200, BSR(z, kFixedDigits));
Line(0, 0);
ForeColor(blackColor);
end;
end; {for}
SetGWorld(GWorldPtr(w), GetMainDevice);
ForeColor(blackColor);
CopyBits(gOffscreen^.portBits, w^.portBits, gOffscreen^.portRect, gOffscreen^.portRect, srcCopy, nil);
end; {Render}
procedure InitTables;
var
i: Longint;
v, scale: Longint;
const
Pi = 3.1416;
function Round2 (l: Longint): Longint;
{Division by 2 with rounding}
begin
if l > 0 then
l := l + 1
else if l < 0 then
l := l - 1;
l := l div 2;
Round2 := l;
end;
begin
for i := 0 to kMaxAngle do
begin
sinTable[i] := Round2(Trunc(kFixedOne * 2 * sin(i * 2 * Pi / kMaxAngle)));
cosTable[i] := Round2(Trunc(kFixedOne * 2 * cos(i * 2 * Pi / kMaxAngle)));
end;
for i := 0 to kMaxRows do
rowTable[i] := i * offScreenRow;
for i := 0 to kMapSizeV do
mapRowTable[i] := i * mapRow;
for i := 0 to kMaxRows do
dyTable[i] := kHalfRows - i * kFixedOne div kFokal;
end; {InitTables}
procedure About; { Reponse to "About" selection }
begin
if 1 = Alert(128, nil) then ;
end; {About}
procedure DoFileMenu (item: integer); { ignored - there's only quit }
begin
case item of
1:
Render;
3:
SkelWhoa; { Tell SkelMain to quit }
end; {case}
end;
procedure Mouse (thePt: Point; t: longint; mods: integer);
begin
end;
procedure Idle;
var
km: KeyMap;
i: Integer;
doRender: Boolean;
begin
repeat
doRender := false;
GetKeys(km);
{Note: Real programs don't use hard-coded key codes (unless they can display the}
{correct keys)!}
if km[37] then {L}
begin
direction := (direction + kMaxAngle - 20) mod kMaxAngle;
doRender := true;
end;
if km[38] then {j}
begin
direction := (direction + 20) mod kMaxAngle;
doRender := true;
end;
if km[34] then {i}
begin
{Move forward}
for i := 1 to 5 do
begin
playerX := BAnd(playerX + cosTable[direction], kMapMaskFixedH);
playerZ := BAnd(playerZ + sinTable[direction], kMapMaskFixedV);
end;
doRender := true;
end;
if km[40] then {k}
begin
{Reverse}
playerX := BAnd(playerX - cosTable[direction], kMapMaskFixedH);
playerZ := BAnd(playerZ - sinTable[direction], kMapMaskFixedV);
doRender := true;
end;
if doRender then
Render;
until not doRender;
end; {Idle}
procedure Update (resized: Boolean);
begin
Render;
{ ForeColor(cyanColor);
PaintRect(w^.portRect);}
end; {Update}
procedure Close;
begin
SkelWhoa;
end; {Close}
procedure Key (ch: char; mods: integer);
var
i: Integer;
begin
{All keyboard handling is done by GetKeys in Idle!}
end; {Key}
procedure Setup;
const
kColorBaseCLUT = 128;
kGrayCLUT = 129;
kScreenCLUT = 130;
kHeightPict = 128;
kColorPict = 129;
var
h, v: Integer;
clut: CTabHandle;
savePort: GrafPtr;
saveDev: GDHandle;
derivata: Integer;
heightPict, colorPict: PicHandle;
palle: PaletteHandle;
begin
GetGWorld(GWorldPtr(savePort), saveDev);
{Create offscreens}
SetRect(boundsRect, 0, 0, kViewAngle * 2 + 5, kMaxRows + 10);
clut := GetCTable(kScreenCLUT);
{$IFC UNDEFINED THINK_PASCAL}
if noErr <> NewGWorld(GWorldPtr(gOffscreen), 8, boundsRect, clut, nil, 0) then
{$ELSEC}
if noErr <> NewGWorld(GWorldPtr(gOffscreen), 8, boundsRect, clut, nil, []) then
{$ENDC}
ExitToShell;
if LockPixels(CGrafPtr(gOffscreen)^.portPixMap) then
;
SetRect(mapBoundsRect, 0, 0, kMapSizeH, kMapSizeV);
{map is the height field}
clut := GetCTable(kGrayCLUT);
{$IFC UNDEFINED THINK_PASCAL}
if noErr <> NewGWorld(GWorldPtr(map), 8, mapBoundsRect, clut, nil, 0) then
{$ELSEC}
if noErr <> NewGWorld(GWorldPtr(map), 8, mapBoundsRect, clut, nil, []) then
{$ENDC}
ExitToShell;
if LockPixels(CGrafPtr(map)^.portPixMap) then
;
{colorScreen is the pixel values to display}
clut := GetCTable(kScreenCLUT);
{$IFC UNDEFINED THINK_PASCAL}
if noErr <> NewGWorld(GWorldPtr(colorScreen), 8, mapBoundsRect, clut, nil, 0) then
{$ELSEC}
if noErr <> NewGWorld(GWorldPtr(colorScreen), 8, mapBoundsRect, clut, nil, []) then
{$ENDC}
ExitToShell;
if LockPixels(CGrafPtr(colorScreen)^.portPixMap) then
;
offscreenPixels := ByteArrPtr(CGrafPtr(gOffscreen)^.portPixMap^^.baseAddr);
mapPixels := ByteArrPtr(CGrafPtr(map)^.portPixMap^^.baseAddr);
colorPixels := ByteArrPtr(CGrafPtr(colorScreen)^.portPixMap^^.baseAddr);
offscreenRow := BitAnd(CGrafPtr(gOffscreen)^.portPixMap^^.rowBytes, $3fff);
mapRow := BitAnd(CGrafPtr(map)^.portPixMap^^.rowBytes, $3fff);
colorRow := BitAnd(CGrafPtr(colorScreen)^.portPixMap^^.rowBytes, $3fff);
SetGWorld(GWorldPtr(map), nil);
heightPict := GetPicture(kHeightPict);
DrawPicture(heightPict, mapBoundsRect);
colorPict := GetPicture(kColorPict);
SetGWorld(GWorldPtr(colorScreen), nil);
DrawPicture(colorPict, mapBoundsRect);
SetGWorld(GWorldPtr(savePort), saveDev);
clut := GetCTable(kScreenCLUT); {Not currently used}
{SetEntries(0, 256, clut^^.ctTable); {applicerar clut på current device}
{palle := GetNewPalette(128);}
{SetPalette(w, palle, true);}
{AnimatePalette(w, clut, 0, 0, 255);}
CopyBits(map^.portBits, w^.portBits, mapBoundsRect, mapBoundsRect, srcCopy, nil);
CopyBits(colorScreen^.portBits, w^.portBits, mapBoundsRect, mapBoundsRect, srcCopy, nil);
playerX := 0;
playerZ := kFixedOne * 30;
playerY := kStartHeight; {50-80 nånstans?}
direction := kMaxAngle div 8;
end;
begin
SkelInit(6, nil); { Initialize }
SkelApple('About Ingemar''s landscape generator…', @About); { Handle Desk Accessories }
m := NewMenu(2, 'File'); { Create Menu }
AppendMenu(m, 'Render/R;(-;Quit/Q');
dummy := SkelMenu(m, @DoFileMenu, nil, true); { Tell Transkel to handle it }
SkelSetSleep(0);
r.top := 50;
r.left := 20;
r.bottom := 300;
r.right := 450;
w := GetNewCWindow(130, nil, WindowPtr(-1));
SetPort(w);
dummy := SkelWindow(w, @Mouse, @Key, @Update, nil, @Close, nil, @Idle, true);
Setup;
InitTables;
SetPort(w);
SkelMain; { loop til quit selected }
SkelClobber; { clean up }
DisposeWindow(w);
end.